package com.example;

import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Test;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;

public class HamcrestTestDemo {

    /**
     * 测试中最常用的equalTo。not内部增加了对equalTo的取反，本质上用的还是equalTo。
     * equalTo使用对象的equals方法来进行比较
     */
    @Test
    public void testTutorial(){
        TestObject first = new TestObject(0L,"123");
        TestObject second = new TestObject(1L,"123");
        TestObject third = new TestObject(0L,"123");
        assertThat(first, not(second));
        assertThat(first, equalTo(third));
        assertThat(second,not(third));

    }

    /**
     * Java中的任何对象都可以，不管任何的比较都会返回true
     */
    @Test
    public void testAnything(){
        assertThat("str",anything());
        assertThat(0,anything());
        assertThat(true,anything());
        assertThat(null,anything());
    }

    /**
     * 有时候我们觉得官方的测试失败消息不是那么的已读，那么自己重新指定错误提示消息。
     */
    @Test
    public void testdescribedAs(){
        String str = "str";
        String otherStr = "otherStr";
        assertThat(str,describedAs("当前的字符串是 %0",anything(),str));
        assertThat(str,describedAs("判断字符串 %0 是否等于 %1",is(str),str,otherStr));
    }


    /**
     * allOf 当内部所有的Matcher都成立时才成立，相当于 &&
     * anyOf 当内部任何一个的Matcher成立时就成立，相当于 ||
     * not 对以上取反
     */
    @Test
    public void testLogical(){
        String str = "testStr testStr";
        assertThat(str,allOf( containsString("test"),containsString("Str"),containsString(" ")  ));
        assertThat(str,anyOf( containsString("test"),containsString("adas"),containsString(" ")  ));
        assertThat(str,allOf( containsString("test"),containsString("adas"),containsString(" ")  ));

    }

    /**
     * 测试Object的一些特性：
     *
     */
    @Test
    public void testObject(){
        TestObject testObject = new TestObject(10L,"12313");
        assertThat(testObject, instanceOf(TestObject.class) );
        assertThat(testObject, instanceOf(Object.class) );
        assertThat(testObject, sameInstance(Object.class) );
    }

    /**
     * 测试JavaBean是否有某个属性
     */
    @Test
    public void testBean(){
        TestObject testObject = new TestObject(10L,"12313");
        assertThat(testObject,hasProperty("id"));
    }


    /**
     * 测试集合
     */
    @Test
    public void testCollections(){
        HashMap<Object, Object> map = new HashMap<>();
        map.put("orgId",123);
        map.put("operator",0);
        assertThat(map,hasKey("orgId"));
        assertThat(map,hasValue(123));

        List<Object> list = Arrays.asList("apple","banana","strawberry");
        assertThat(list,hasItem("apple"));
        assertThat(list.toArray(),hasItemInArray("apple"));
    }

    /**
     * 测试数字的比较
     */
    @Test
    public void testNumber(){
        int score = 90;
        int total = 100;
        assertThat(score,lessThan(total));
//        assertThat(score,greaterThan(total));
//        assertThat(score,greaterThanOrEqualTo(total));
//        assertThat(score,lessThanOrEqualTo(total));
    }

    @Test
    public void testText(){
        String text = "Hamcrest comes bundled with lots of useful matchers, but you’ll probably find that you need to create your own from time to time to fit your testing needs. This commonly occurs when you find a fragment of code that tests the same set of properties over and over again (and in different tests), and you want to bundle the fragment into a single assertion. By writing your own matcher you’ll eliminate code duplication and make your tests more readable!";
        assertThat(text,containsString("comes"));
        assertThat(text,startsWith("Hamcrest"));
        assertThat(text,endsWith("readable!"));
        assertThat(text,equalTo("readable!"));

    }

    /**
     * 测试自定义的匹配器
     */
    @Test
    public void testCustomMatcher(){
        String o = "";
        assertThat(o,new isSuccess());
        assertThat(null,new isSuccess());
    }


    /**
     * 只要对象不为空就为成功
     */
    public static class isSuccess extends TypeSafeMatcher{

        @Override
        protected boolean matchesSafely(Object o) {
            return o != null;
        }

        @Override
        public void describeTo(Description description) {
            description.appendText("is success");
        }
    }


    public static class TestObject{
        Long id;
        String msg;

        public TestObject(Long id, String msg) {
            this.id = id;
            this.msg = msg;
        }

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public String getMsg() {
            return msg;
        }

        public void setMsg(String msg) {
            this.msg = msg;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            TestObject that = (TestObject) o;
            return id.equals(that.id) &&
                    msg.equals(that.msg);
        }

        @Override
        public int hashCode() {
            return Objects.hash(id, msg);
        }
    }
}
